package cbfg.state

import android.util.SparseArray
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.annotation.LayoutRes
import androidx.core.util.*
import androidx.core.view.isVisible

/**
 * @Description: 状态布局管理
 * @Author: TomHawk
 * @CreateDate: 2022/8/18 14:44
 */

/** 状态布局及按钮点击回调 */
typealias StateClickListener = (helper: StateLayoutHelper, state: Int, view: View) -> Unit

class StateLayoutHelper private constructor(builder: Builder) {
    private val container: ViewGroup
    private var stateClickListener: StateClickListener? = null

    /** 存放布局集合 */
    private val stateLayouts: SparseArray<Any>

    private var stateParams: SparseArray<LayoutParams>? = null

    private var layoutHandler: LayoutHandler? = null

    /** 用于暂存数据使用 */
    var extra: Any? = null

    init {
        container = builder.container
        stateClickListener = builder.stateClickListener
        layoutHandler = builder.layoutHandler
        stateLayouts = SparseArray<Any>(builder.states.size())

        if (builder.stateParams.isNotEmpty()) {
            stateParams = builder.stateParams
        }

        builder.states.forEach { state, layout ->
            if (layout is View) {
                addStateView(state, layout)
            } else {
                val params = stateParams?.get(state)
                if (params == null || params.lazyInflate) {
                    stateLayouts.put(state, layout)
                } else {
                    val stateView = LayoutInflater.from(container.context)
                        .inflate(layout as Int, container, false)
                    addStateView(state, stateView)
                }
            }
        }

        builder.states.clear()
        builder.layoutHandler = null
    }

    private fun addStateView(state: Int, view: View) {
        stateLayouts.put(state, view)
        setListeners(view, state)

        //判断如果外部有处理则不用再处理，否则默认处理布局添加:
        if (view.parent == null && layoutHandler?.handle(container, state, view) != true) {
            container.addView(view, stateParams?.get(state)?.indexInContainer ?: -1)
        }

        stateParams?.run {
            this.remove(state)
            if (this.isEmpty()) {
                stateParams = null
            }
        }
    }

    /**
     * 显示状态布局
     * @param image 状态图，如果为 -1 不设置
     * @param message 提示文本，如果为 null 不设置；对应 View id : tvStateTip
     * @param title 标题，如果为 null 不设置；对应 View id : tvStateTitle
     */
    fun showState(
        state: Int,
        @DrawableRes image: Int = -1,
        message: String? = null,
        title: String? = null
    ) {
        if (!inflate(state)) {
            return
        }
        //遍历状态布局集合，然后切换显示和隐藏:
        stateLayouts.forEach { key, view ->
            if (view is View) {
                view.isVisible = key == state
            }
        }

        val layoutView = stateLayouts[state] as View
        if (image != -1) {
            layoutView.find<ImageView>(R.id.ivStateImage)?.setImageResource(image)
        }
        if (message != null) {
            layoutView.find<TextView>(R.id.tvStateTip)?.text = message
        }
        if (title != null) {
            layoutView.find<TextView>(R.id.tvStateTitle)?.text = title
        }
    }

    private inline fun <reified T> View.find(viewId: Int): T? {
        val view = this.findViewById<View>(viewId)
        return if (view is T) view else null
    }

    /**
     * 隐藏指定的状态布局
     * @param state 状态 id
     */
    fun hideState(state: Int) {
        val view = stateLayouts[state]
        if (view is View) {
            view.visibility = View.GONE
        }
    }

    /**
     * 隐藏所有状态
     */
    fun hideStates() {
        stateLayouts.keyIterator().forEach { hideState(it) }
    }

    /**
     * 移除指定的状态，移除后再操作改状态将没有效果
     * @param state 状态 id
     */
    fun removeState(state: Int) {
        val view = stateLayouts[state] ?: return
        stateLayouts.remove(state)
        if (view is View && view.parent != null) {
            container.removeView(view)
        }
    }

    /**
     * 清除所有状态布局
     */
    fun clearStates() {
        stateLayouts.valueIterator().forEach {
            if (it is View) {
                container.removeView(it)
            }
        }
        stateLayouts.clear()
        stateClickListener = null
    }

    /**
     * 查询指定状态是否显示
     * @param state 状态 id
     */
    fun isStateVisible(state: Int): Boolean {
        val view = stateLayouts[state]
        return view is View && view.visibility == View.VISIBLE
    }

    /**
     * 判断填充 ViewStub
     * @param state 状态 id
     * @return 布局是否 inflate 成功
     */
    private fun inflate(state: Int): Boolean {
        val layout = stateLayouts[state] ?: return false
        if (layout is Int) {
            val stateView = LayoutInflater.from(container.context).inflate(layout, container, false)
            addStateView(state, stateView)
        }
        return true
    }

    private fun setListeners(view: View, state: Int) {
        val clickListener = View.OnClickListener { stateClickListener?.invoke(this, state, it) }
        view.setOnClickListener(clickListener)
        view.findViewById<View>(R.id.btnStateRetry)?.setOnClickListener(clickListener)
        view.findViewById<View>(R.id.btnStateOK)?.setOnClickListener(clickListener)
        view.findViewById<View>(R.id.btnStateCancel)?.setOnClickListener(clickListener)
        view.findViewById<View>(R.id.btnStateClose)?.setOnClickListener(clickListener)
    }

    /**
     * @param container 状态布局的父容器
     */
    class Builder(internal val container: ViewGroup) {
        internal var layoutHandler: LayoutHandler? = null
        internal var stateClickListener: StateClickListener? = null
            private set

        /** 存储状态信息及对应的布局 View 或 LayoutRes */
        internal val states = SparseArray<Any>(5)

        internal val stateParams = SparseArray<LayoutParams>(5)

        /**
         * @param layoutHandler 布局处理器
         */
        fun config(layoutHandler: LayoutHandler): Builder {
            this.layoutHandler = layoutHandler
            return this
        }

        /**
         * 添加状态
         * @param state 状态 id
         * @param layoutRes 状态对应的布局资源
         * @param lazyInflate 是否延迟填充，true 的话使用 ViewStub 进行保存，默认 true
         * @param indexInContainer 表示添加到容器中的第几个位置
         */
        fun addState(
            state: Int,
            @LayoutRes layoutRes: Int,
            lazyInflate: Boolean = true,
            indexInContainer: Int = -1
        ): Builder {
            states.put(state, layoutRes)
            if (!lazyInflate || indexInContainer != -1) {
                stateParams.put(state, LayoutParams(lazyInflate, indexInContainer))
            }
            return this
        }

        /**
         * 添加状态
         * @param state 状态 id
         * @param view 状态 View
         */
        fun addState(state: Int, view: View): Builder {
            states.put(state, view)
            return this
        }

        /** 移除指定的状态 */
        fun removeState(state: Int): Builder {
            states.remove(state)
            stateParams.remove(state)
            return this
        }

        /**
         * 设置状态布局及按钮点击事件
         * @param stateClickListener listener
         */
        fun setStateClickListener(stateClickListener: StateClickListener?): Builder {
            this.stateClickListener = stateClickListener
            return this
        }

        fun build(): StateLayoutHelper {
            return StateLayoutHelper(this)
        }
    }

    /**
     * @param lazyInflate 是否延迟填充
     * @param indexInContainer 表示添加到容器中的第几个位置
     */
    class LayoutParams(val lazyInflate: Boolean, val indexInContainer: Int)
}